/**
 * @class   wosh::gui::WoshTableModel
 * @brief   
 *          
 *          
 *
 ****************************************************************************
 * @version $Id: WoshTableModel.h 2878 2010-08-09 01:11:12Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Gui_WoshTableModel_H__
 #define __WOSH_Gui_WoshTableModel_H__

 #include <core/Variant.h>
 #include <core/List.h>
 #include <core/Table.h>
 #include <core/MethodsCommon.h>
 #include <core/Permission.h>
 #include <core/SecurityManager.h>
 #include <framework/gui/GuiUtilities.h>
 #include <framework/gui/IWidgetSerializable.h>

 #include <QtGui/QWidget>
 #include <QAbstractTableModel>
 #include <QVBoxLayout>
 #include <QTableView>
 #include <QHeaderView>
 #include <QItemDelegate>
 #include <QtGui/QMenu>
 #include <QtGui/QLabel>
 #include <QtGui/QSpinBox>
 #include <QtGui/QDoubleSpinBox>
 #include <QtGui/QDateTimeEdit>
 #include <QtGui/QListWidget>


namespace wosh {
 namespace gui {


class GenericItemDelegate : public QItemDelegate
 {
	Q_OBJECT

	public:
		GenericItemDelegate(QObject *parent = 0) : QItemDelegate(parent) { }

		virtual ~GenericItemDelegate() { }

	public:
		QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;

		void setEditorData(QWidget *editor, const QModelIndex &index) const;
		void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;

		void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const {
			(void)index;
			editor->setGeometry(option.rect);
		 }

}; // class def




class WoshTableModel : public QAbstractTableModel
 {
	Q_OBJECT

	public:
		WoshTableModel(const wosh::Table* table, QObject *parent = 0);

		virtual ~WoshTableModel();

	public:
		void setPermissionCol(int mode)				{ this->permissionCol = mode; }

		void setPermissionType( Permission::PERMISSION_TYPE type )
													{ this->permissionType = type; }

		wosh::Table* getDataTable()					{ return this->dataTable; }
		const wosh::Table* getDataTable() const 	{ return this->dataTable; }

		void loadTable( const wosh::Table* table );

		void acquireTable( wosh::Table* table);

		void analyzeTable();

		void updateTable( const wosh::Table* table );

	public:
		void setSecurityToken(SecurityToken* msec) {
			 if ( this->editingUserSecurity  != NULL )
				delete this->editingUserSecurity;
			 this->editingUserSecurity = msec;
		 }

		SecurityToken* getSecurityToken()				{ return this->editingUserSecurity; }
		const SecurityToken* getSecurityToken() const	{ return this->editingUserSecurity; }

	public:
		virtual int rowCount(const QModelIndex &parent = QModelIndex()) const {
			(void)parent;
			if ( this->dataTable == NULL ) return 0;
			return this->dataTable->getRows();
		 }

		virtual int columnCount(const QModelIndex &parent = QModelIndex()) const {
			(void)parent;
			if ( this->dataTable == NULL ) return 0;
			return this->dataTable->getCols();
		 }

		virtual QVariant data(const QModelIndex &index, int role) const;

		virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;

	public: // sortable
		void sort ( int column, Qt::SortOrder  order = Qt::AscendingOrder ) {
			if ( this->dataTable == NULL ) return;
			if ( column < 0 ) return;
			this->dataTable->sortByColumn((unsigned int)column, (short)order);
			reset();
		 }

	public: // editable
		 Qt::ItemFlags flags(const QModelIndex &index) const;

		bool setData(const QModelIndex &index, const QVariant &value, int role);

/*
tablePermission
		 bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) {
			 beginInsertRows(QModelIndex(), position, position+rows-1);
			 for (int row = 0; row < rows; ++row) {
				 stringList.insert(position, "");
			 }
			 endInsertRows();
			 return true;
		 }

		 bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) {
			 beginRemoveRows(QModelIndex(), position, position+rows-1);
			 for (int row = 0; row < rows; ++row) {
				 stringList.removeAt(position);
			 }
			 endRemoveRows();
			 return true;
		 }
*/

	signals:
		void tableCell_changed( unsigned int row, unsigned int col, ISerializable* newValue );

	protected:
		bool evalAuthorization( const Permission* permissions, Permission::PERMISSION_TYPE operation ) const {
			if ( this->editingUserSecurity == NULL )
				this->editingUserSecurity = GuiSession::getInstance().createToken();
			return SecurityManager::evalAuthorization(this->editingUserSecurity, permissions, operation );
		 }

	protected:
		wosh::Table* dataTable;
		int permissionCol;
		Permission tablePermission;
		mutable SecurityToken* editingUserSecurity;
		int forceKeyCol;
		Permission::PERMISSION_TYPE permissionType;

}; // class def


class WidgetUpdateBar;

class WoshTableView :	public QTableView,
						public virtual IWidgetSerializableT<wosh::Table>
 {
	Q_OBJECT

	WOSH_WIDGET_SERIALIZABLE(wosh::gui::WoshTableView)

	public:
		WoshTableView( QWidget* parent = NULL );
		virtual ~WoshTableView();

	public:
		inline const WoshTableModel* getTableModel() const		{ return this->wTableModel; }
		inline WoshTableModel* getTableModel()					{ return this->wTableModel; }

	public:
		const ISerializable* getItem( int row, int column ) const {
			if ( this->wTableModel == NULL ) return NULL;
			if ( this->wTableModel->getDataTable() == NULL ) return NULL;
			if ( row < 0 )
				return this->wTableModel->getDataTable()->getHeaderHorizontal(column);
			if ( column < 0 )
				return this->wTableModel->getDataTable()->getHeaderVertical(row);
			return this->wTableModel->getDataTable()->get(row, column);
		 }
		template<class DYNAMIC_CAST>
		const DYNAMIC_CAST* getItem( int row, int column ) const {
			return dynamic_cast<const DYNAMIC_CAST*>( this->getItem(row, column) );
		 }

																				inline Variant getCurrentItemAsVariantAtCol( int column ) const {
																					return getItemAsVariant( this->currentIndex().row(), column );
																				 }

		Variant getItemAsVariant( int row, int column ) const {
			const ISerializable* obj = getItem( row,column );
			if ( obj == NULL ) return Variant();
			if ( !obj ->isKindOf<Variant>() ) return Variant();
			const Variant* data = dynamic_cast<const Variant*>(obj);
			if ( data == NULL ) return Variant();
			return *data;
		 }

	public slots:
		virtual WRESULT loadObject( const wosh::Table* object ) {
			if ( object == NULL ) {
				this->wTableModel->loadTable(NULL);
				return WRET_OK;
			 }
			this->wTableModel->updateTable(object);
			this->horizontalHeader()->setSortIndicator(-1, Qt::AscendingOrder);
			return WRET_OK;
		 }

		virtual WRESULT saveObject( wosh::Table* object ) const {
			if ( object == NULL ) return WRET_ERR_PARAM;
			return WRET_OK;
		 }

	signals:
																				void updated();
																				void postMessage( Message* message );

	protected:
		WoshTableModel* wTableModel;


}; // class def

class WidgetTablePagingControl;

class WidgetTable : public QWidget
 {
	Q_OBJECT

	public:
		WidgetTable(QWidget *parent = 0);
		~WidgetTable();

	public:
		inline void setMethodList( const std::string& name )	{ this->methodList = name; }
		inline void setMethodRetrieve( const std::string& name ) { this->methodRetrieve = name; }

		inline void setMethodRetrieveIndex( int index )			{ this->methodRetrieveIndex = index; }
		inline void setMethodRetrieveAuto( bool value )			{ this->methodRetrieveAuto = value; }

		inline void setResizeStretch( int value )				{ this->resizeStretch = value; }
		inline void setResizeMode( int value )					{ this->resizeMode = value; }

		inline const WoshTableView* getTableView() const		{ return this->tableView; }
		inline WoshTableView* getTableView()					{ return this->tableView; }

		inline const WoshTableModel* getTableModel() const		{ return this->tableView->getTableModel(); }
		inline WoshTableModel* getTableModel()					{ return this->tableView->getTableModel(); }

		inline const WidgetUpdateBar* getUpdateBar() const		{ return this->wUpdateBar; }
		inline WidgetUpdateBar* getUpdateBar()					{ return this->wUpdateBar; }

	public slots:
		void refreshData();

		void evalResponse( const Response* response);


	public:
		inline const ISerializable* getCurrentItem() const {
			return this->tableView->getItem( this->tableView->currentIndex().row(),this->tableView->currentIndex().column() );
		 }

		inline Variant getCurrentItemAsVariantAtCol( int column ) const {
			return this->tableView->getItemAsVariant( this->tableView->currentIndex().row(), column );
		 }

	signals:
		void updated();
		void postMessage( Message* message );

		void tableContextMenuRequested( const QPoint& pos, const QModelIndex& index );
		void tableItemDoubleClicked( const QModelIndex& index );
		void tableItemClicked( const QModelIndex& index );

	protected slots:
		void tableItem_ContextMenu( const QPoint& pos );
		void tableItem_Clicked( const QModelIndex& index );
		void tableItem_DoubleClicked( const QModelIndex& index );

		void horizontalHeader_ContextMenu( const QPoint& pos );
	//	void paging_rangeSelected( long start_index, long end_index );

	protected:
		Request* createRequestList();
		Request* createRequestRetrieve( ISerializable* args = NULL );

	protected:
		QVBoxLayout* vLayout;
		WoshTableView* tableView;
		WidgetUpdateBar* wUpdateBar;
		WidgetTablePagingControl* wPagingControl;

	protected:
		void rebuildMenus();
		QMenu* menuHHeader;
		QAction* menuHHeaderTitle;
		QAction* menuHHeaderRetrieveCols;
		QAction* menuHHeaderDefaultCols;
		QAction* menuHHeaderPaging;

	protected:
		std::string methodList;
		std::string methodRetrieve;
		int methodRetrieveIndex;
		bool methodRetrieveAuto;

	protected: // cached info about table
		List fieldsAll; // all fields
		bool retrievingFields;

	protected: // current configuration:
		int resizeMode;
		int resizeStretch;

}; // class def


class WidgetTablePagingControl : public QWidget
 {
	Q_OBJECT

	public:
		WidgetTablePagingControl(QWidget *parent = 0);
		~WidgetTablePagingControl() { }

	//protected slots:
	public:
		inline unsigned int getCount() const			{ return this->count; }
		void setCount( unsigned int value );

		unsigned int getIndexStart() const;
		unsigned int getIndexEnd() const;
		inline unsigned int getPageSize() const			{ return this->spinPageLen->value(); }

	protected slots:
		void spinPage_valueChanged( int value );
		void spinPageLen_valueChanged( int value );

	signals:
		void rangeSelected( long start_index, long end_index );

	protected:
		void updatePageCount();

	protected:
		unsigned int count;

	protected:
		QLabel* lblPageCount;
		QSpinBox* spinPage;
		QSpinBox* spinPageLen;

}; // class def


 }; // namespace gui
}; // namespace wosh

#endif //__WOSH_Gui_WoshTableModel_H__
